/**
 * Created by Yu Jin Xian on 2016/12/14.
 */
function newFunction() {
    function sum(num1, num2) {
        return num1 + num2;
    }

    function definite() {
        var sum = function (num1, num2) {
            return num1 + num2;
        }
    }

    function constructor() {
        var sum = new Function('num1', 'num2', 'return num1 + num2');   // 不推荐
    }

    function multiVariables() {
        function sum(num1, num2) {
            return num1 + num2;
        }

        alert(sum(10, 10));                         // 20
        var anotherSum = sum;
        alert(anotherSum(10, 10));                  // 20
        sum = null;
        alert(anotherSum(10, 10));                  // 20
    }
}

function noOverload() {
    function addSomeNumber(num) {
        return num + 100;
    }

    function addSomeNumber(num) {
        return num + 200;
    }

    var result = addSomeNumber(100);                // 300

    function cover() {
        var addSomeNumber = function (num) {
            return num + 100;
        };

        addSomeNumber = function (num) {
            return num + 200;
        };

        var result = addSomeNumber(100);            // 300
    }
}

function declaration() {
    alert(sum(10, 10));

    function sum(num1, num2) {
        return num1 + num2;
    }

    function initialization() {
        alert(cumsum(10, 10));
        var cumsum = function (num1, num2) {
            return num1 + num2;
        }
    }
}

function functionAsAnArgument() {
    function callSomeFunction(someFunction, someArgument) {
        return someFunction(someArgument);
    }

    function add10(num) {
        return num + 10;
    }

    var result = callSomeFunction(add10, 10);
    alert(result);                                  // 20

    function getGreeting(name) {
        return 'Hello, ' + name;
    }

    var result2 = callSomeFunction(getGreeting, 'Nicholas');
    alert(result2);                                 // "Hello, Nicholas"

    function createComparisonFunction(propertyName) {
        return function (object1, object2) {
            var value1 = object1[propertyName];
            var value2 = object2[propertyName];
            if (value1 < value2) {
                return -1;
            } else if (value1 > value2) {
                return 1;
            } else {
                return 0;
            }
        }
    }

    var data = [{name: 'Zachary', age: 28}, {name: 'Nicholas', age: 29}];
    data.sort(createComparisonFunction('name'));
    alert(data[0].name);
    data.sort(createComparisonFunction('age'));
    alert(data[0].name);
}

function functionTypeArguments() {
    function factorial(num) {
        if (num <= 1) {
            return 1;
        } else {
            return num * factorial(num - 1);
        }
    }

    function callee() {
        function factorial(num) {
            if (num <= 1) {
                return 1;
            } else {
                return num * arguments.callee(num - 1);
            }
        }

        var trueFactorial = factorial;
        factorial = function () {
            return 0;
        };
        alert(trueFactorial(5));                    // 120
        alert(factorial(5));                        // 0
    }

    function thisEnv() {
        window.color = 'red';
        var o = {color: 'blue'};

        function sayColor() {
            alert(this.color);
        }

        sayColor();                             // "red"

        o.sayColor = sayColor;
        o.sayColor();                           // "blue"

        function outer() {
            inner();
        }

        function inner() {
            alert(inner.caller);
        }

        outer();

        function caller() {
            function outer() {
                inner();
            }

            function inner() {
                alert(arguments.callee.caller);
            }

            outer();
        }
    }
}

function functionPropertiesAndMethods() {
    function sayName(name) {
        alert(name);
    }

    function sum(num1, num2) {
        return num1 + num2;
    }

    function sayHi() {
        alert('hi');
    }

    alert(sayName.length);                          // 1
    alert(sum.length);                              // 2
    alert(sayHi.length);                            // 0

    function apply() {
        function sum(num1, num2) {
            return num1 + num2;
        }

        function callSum1(num1, num2) {
            return sum.apply(this, arguments);      // 传入 arguments 对象
        }

        function callSum2(num1, num2) {
            return sum.apply(this, [num1, num2]);   // 传入数组
        }

        alert(callSum1(10, 10));                    // 20
        alert(callSum2(10, 10));                    // 20
    }

    function call() {
        function sum(num1, num2) {
            return num1 + num2;
        }

        function callSum(num1, num2) {
            return sum.call(this, num1, num2);      // 传入数组
        }

        alert(callSum(10, 10));                     // 20

        window.color = 'red';
        var o = {color: 'blue'};

        function sayColor() {
            alert(this.color);
        }

        sayColor();                                 // "red"

        sayColor.call(this);                        // "red"
        sayColor.call(window);                      // "red"
        sayColor.call(o);                           // "blue"
    }

    function bind() {
        window.color = 'red';
        var o = {color: 'blue'};

        function sayColor() {
            alert(this.color);
        }

        var objectSayColor = sayColor.bind(o);
        objectSayColor();                           // "blue"
    }
}